Deep Learning on Cloud Nine(整理版)
原始资料: CS197 Harvard Lectures 14 & 15 - Deep Learning on Cloud Nine created: 2026-07-10 11:01 整理说明: 本版本结合原始笔记和可读取的原始教程重排、补全和翻译。原教程包含 AWS EC2 教程,但本笔记按当前实践选择暂时跳过 AWS 创建流程,重点整理组内 GPU 使用、GPU 监控、数据下载和 CheXzero 训练准备。
内容简要概括
这节课讨论如何从本地开发转向云端或远程 GPU 环境进行 deep learning 实验,核心是让代码、数据加载和训练流程真正使用 GPU。原教程以 AWS EC2 为主要平台,但当前笔记将实践重点切换到组内 GPU:需要先确认 GPU 状态,再配置 conda 环境、监控训练资源、下载大规模数据,并为 CheXzero / MIMIC-CXR 这类医学影像训练任务准备数据。最值得记住的是:有 GPU 不等于代码会自动使用 GPU,模型、输入张量、DataLoader 参数和依赖版本都需要一起检查。
GPU、nvidia-smi、CUDA、conda、W&B、DataLoader、num_workers、batch size、wget、tmux、PhysioNet、MIMIC-CXR、CheXzero、HDF5
目录
- 1. 学习目标与实践取舍
- 2. 远程 GPU 环境准备
- 3. GPU 状态查看与监控
- 4. 将训练代码迁移到 GPU
- 5. 训练速度优化思路
- 6. 使用 wget 下载网络数据
- 7. CheXzero 与 MIMIC-CXR 数据准备
- 8. 常见问题与排查
- 原始教程要点
1. 学习目标与实践取舍
原始教程的主题是 “Deep Learning on Cloud Nine”,主要通过 AWS EC2 演示如何创建 GPU instance、连接远程机器、修改训练代码并运行 CheXzero。当前笔记的实际取舍是:
- 暂时跳过 AWS 服务器创建和连接教程。
- 改为使用组内已有 GPU 服务器。
- 保留原教程中与 GPU 训练、环境配置、数据下载、CheXzero 调试相关的内容。
整理后的学习目标可以概括为:
- 能判断远程机器是否有可用 GPU,以及 GPU 当前是否被训练任务占用。
- 能理解
nvidia-smi和nvidia-smi dmon的关键指标。 - 能把 PyTorch 训练代码显式迁移到
cudadevice。 - 能用
wget、tmux和磁盘检查命令处理长时间、大规模数据下载。 - 能理解 CheXzero 训练前的数据目录、依赖和常见报错。
2. 远程 GPU 环境准备
2.1 创建或激活 conda 环境
在组内 GPU 服务器上,通常需要为课程代码或项目代码单独创建环境,避免污染已有环境。
conda create -n cs197-gpu python=3.9
conda activate cs197-gpu
如果服务器上的 conda 尚未初始化,可能需要先运行:
conda init
有些预装 AMI 或服务器环境中会使用:
source activate pytorch
source activate 与 conda activate 的目的都是激活环境;区别在于某些远程环境第一次连接时 conda shell hook 尚未配置好,source activate 更容易直接可用。
2.2 推荐的基本检查
进入服务器后,先确认当前机器、路径和磁盘空间:
hostname
pwd
df -h
含义如下:
| 命令 | 作用 | 何时使用 |
|---|---|---|
hostname |
查看当前连接到哪台机器 | 防止误在本地或错误服务器上运行训练 |
pwd |
查看当前工作目录 | 下载数据、运行脚本前确认路径 |
df -h |
查看各挂载点磁盘空间,-h 表示 human-readable |
下载大型数据集前确认空间是否足够 |
3. GPU 状态查看与监控
3.1 一次性查看 GPU 状态
最常用命令是:
nvidia-smi
示例输出:
❯ nvidia-smi
Fri Jul 10 11:52:35 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 575.57.08 Driver Version: 575.57.08 CUDA Version: 12.9 |
|-----------------------------------------+------------------------+----------------------|
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 5090 On | 00000000:01:00.0 Off | N/A |
| 0% 37C P8 7W / 575W | 15MiB / 32607MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 2633 G /usr/lib/xorg/Xorg 4MiB |
+-----------------------------------------------------------------------------------------+
这份输出可以按几个区域理解:
| 字段 | 含义 | 解读方式 |
|---|---|---|
NVIDIA-SMI |
nvidia-smi 工具版本 |
主要用于确认工具可用 |
Driver Version |
NVIDIA driver 版本 | 影响 CUDA / PyTorch 兼容性 |
CUDA Version |
driver 支持的最高 CUDA runtime 版本 | 不是当前 PyTorch 一定使用的 CUDA 版本 |
GPU Name |
GPU 型号 | 例如 NVIDIA GeForce RTX 5090 |
Temp |
GPU 温度 | 长时间训练时需要关注是否异常过热 |
Pwr:Usage/Cap |
当前功耗 / 最大功耗 | 可辅助判断 GPU 是否在工作 |
Memory-Usage |
显存占用 | 判断模型、batch size 或其他进程是否占用显存 |
GPU-Util |
GPU 计算利用率 | 如果训练时长期接近 0%,说明代码可能没有真正使用 GPU,或瓶颈在数据加载 |
Processes |
当前占用 GPU 的进程 | 用于识别谁在用显存,以及是否有残留进程 |
从示例看,显存只占用 15MiB / 32607MiB,GPU-Util 为 0%,说明 GPU 基本空闲。/usr/lib/xorg/Xorg 只占用少量显存,通常是图形系统进程,不是训练任务。
3.2 持续监控 GPU 状态
训练时可以每秒刷新一次:
watch -d -n 1 nvidia-smi
参数解释:
watch: 周期性执行后面的命令。-n 1: 每 1 秒刷新一次。-d: 高亮显示与上一次输出不同的部分,方便观察显存、功耗、利用率变化。nvidia-smi: 被重复执行的实际命令。
这个命令适合在另一个 terminal 或 tmux pane 中长期观察训练是否真的用上 GPU。
3.3 使用 dmon 查看动态指标
nvidia-smi dmon 可以按行输出 GPU 动态指标,更适合观察趋势或复制日志。
nvidia-smi dmon -s pucm -d 1 -o T
参数解释:
dmon: device monitoring,以表格流形式监控设备。-s pucm: 选择输出指标组。p: power,即功耗相关指标。u: utilization,即 GPU / memory / encoder / decoder 利用率。c: clock,即显存频率和核心频率。m: memory,即 framebuffer / BAR1 等显存信息。
-d 1: 每 1 秒采样一次。-o T: 输出时间戳,方便对齐训练日志。
示例输出:
Time gpu pwr gtemp mtemp sm mem enc dec jpg ofa mclk pclk fb bar1 ccpm
#HH:MM:SS Idx W C C % % % % % % MHz MHz MB MB MB
16:18:56 0 17 40 - 0 0 0 0 0 0 810 24 15 3 0
16:18:57 0 10 40 - 0 0 0 0 0 0 405 24 15 3 0
16:18:58 0 9 39 - 0 0 0 0 0 0 405 24 15 3 0
16:18:59 0 9 39 - 0 0 0 0 0 0 405 24 15 3 0
16:19:00 0 9 39 - 0 0 0 0 0 0 405 24 15 3 0
16:19:01 0 9 39 - 0 0 0 0 0 0 405 24 15 3 0
16:19:02 0 9 39 - 0 0 0 0 0 0 405 25 15 3 0
常用指标解释:
| 指标 | 含义 | 观察重点 |
|---|---|---|
gpu |
GPU 编号 | 多卡机器上用于区分设备 |
pwr |
当前功耗,单位 W | 训练时通常会明显高于空闲状态 |
gtemp |
GPU core 温度 | 长时间高温需要关注散热 |
mtemp |
显存温度 | 某些 GPU 不提供该值,会显示 - |
sm |
Streaming Multiprocessor 利用率 | 近似反映核心计算繁忙程度 |
mem |
显存带宽利用率 | 数据搬运或 memory-bound 任务会更高 |
mclk |
memory clock | 显存频率 |
pclk |
processor / graphics clock | GPU 核心频率 |
fb |
framebuffer memory 使用量,单位 MB | 近似理解为显存占用 |
bar1 |
BAR1 memory 使用量 | GPU 映射到 CPU 地址空间的内存窗口,通常不是训练调优的首要指标 |
如果训练运行时 sm、mem、pwr 都长期很低,而 CPU 或磁盘很忙,常见原因是 DataLoader 太慢、数据在 CPU 侧预处理过重,或代码没有把 model / tensor 移到 GPU。
4. 将训练代码迁移到 GPU
4.1 检查 CUDA 是否可用
PyTorch 代码需要显式检查 CUDA:
use_cuda = torch.cuda.is_available()
if use_cuda:
device = torch.device("cuda")
else:
device = torch.device("cpu")
这一步的作用是让代码在有 GPU 和没有 GPU 的机器上都能运行。不能只依赖机器有 GPU,因为 driver、CUDA、PyTorch 版本或环境变量都可能导致 torch.cuda.is_available() 为 False。
4.2 将 model 和 tensor 移到 device
模型创建后需要移动到 GPU:
model = Net().to(device)
训练和测试循环中,输入数据和标签也要移动到同一个 device:
def train(args, model, train_loader, optimizer, epoch, device):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
...
def test(model, test_loader, device):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
...
如果 model 在 GPU 上但 data 仍在 CPU 上,通常会出现 device mismatch 报错;如果两者都留在 CPU 上,即使服务器有 GPU,训练也不会自动加速。
4.3 为 DataLoader 设置 CUDA 相关参数
原教程示例中,在 CUDA 可用时会更新训练和测试的 DataLoader 参数:
use_cuda = torch.cuda.is_available()
if use_cuda:
device = torch.device("cuda")
cuda_kwargs = {"num_workers": 1, "shuffle": True}
train_kwargs.update(cuda_kwargs)
test_kwargs.update(cuda_kwargs)
else:
device = torch.device("cpu")
注意:原教程片段里出现过 numworkers,实际 PyTorch DataLoader 参数名应为 num_workers。
4.4 记录训练时间与 W&B 日志
为了比较 CPU、GPU、不同 batch size 或不同 num_workers 的速度,需要记录每个 epoch 的耗时:
import time
for epoch in range(1, args.epochs + 1):
t0 = time.time()
train(args, model, train_loader, optimizer, epoch, device)
t_diff = time.time() - t0
print(f"Elapsed time is {t_diff}")
test_loss, test_acc = test(model, test_loader, device)
scheduler.step()
如果使用 W&B,可以记录 loss、accuracy 和训练耗时:
import wandb
wandb.init(config={"train_args": train_kwargs, "test_args": test_kwargs})
for epoch in range(1, args.epochs + 1):
t0 = time.time()
train(args, model, train_loader, optimizer, epoch, device)
t_diff = time.time() - t0
test_loss, test_acc = test(model, test_loader, device)
scheduler.step()
wandb.log(
{"test_loss": test_loss, "test_acc": test_acc, "time_taken": t_diff},
step=epoch,
)
wandb.finish()
5. 训练速度优化思路
5.1 判断瓶颈在哪里
GPU 训练慢不一定是 GPU 算力不够。常见瓶颈包括:
- 代码没有真正使用 GPU。
- batch size 太小,GPU 显存和计算单元没有被充分利用。
- DataLoader 太慢,GPU 等待 CPU 读取和预处理数据。
- 磁盘或网络文件系统读取慢。
- PyTorch、CUDA、driver 版本不匹配。
建议同时观察:
nvidia-smi/nvidia-smi dmon的 GPU 利用率和显存。- 训练日志中的每个 epoch 耗时。
- CPU、磁盘和数据加载速度。
5.2 调整 batch size
如果显存占用很低,可以尝试增大 batch size:
python main_working.py --batch-size=128
原教程中提到,从默认 64 增加到 128 不一定显著加速,因为示例模型较小,主要瓶颈可能不是模型计算,而是数据加载或内存访问。实际项目中需要结合显存、loss 稳定性和吞吐量一起判断。
5.3 调整 num_workers
num_workers 控制 DataLoader 用多少个子进程加载数据。更多 worker 可以提前准备下一个 batch,让 GPU 不必等待数据读取。
原教程中,g5.4xlarge 的推荐尝试值是 16:
train_kwargs.update({"num_workers": 16, "shuffle": True})
但 num_workers 不是越大越好。过大可能导致:
- CPU 进程过多,反而上下文切换严重。
- 内存占用上升。
- 文件系统压力过大。
- 在共享服务器上影响他人任务。
实践中可以从 1、2、4、8、16 逐步试,并记录 epoch 时间。
6. 使用 wget 下载网络数据
6.1 下载整个目录的典型写法
PhysioNet 数据集通常需要递归下载,形式大致如下:
wget -r -N -c -np \
--user YOUR_PHYSIONET_USERNAME \
--ask-password \
DATASET_URL
参数解释:
| 参数 | 含义 |
|---|---|
-r |
recursive,递归下载目录中的文件 |
-N |
timestamping,只下载远端更新过或本地不存在的文件 |
-c |
continue,断点续传 |
-np |
no-parent,不爬到上级目录 |
--user |
指定需要认证的数据集用户名 |
--ask-password |
交互式输入密码,避免把密码写进命令历史 |
DATASET_URL |
数据集目录或文件链接 |
对于 PhysioNet,下载前通常需要登录账号并获得对应数据集权限。不要把账号、密码或 token 写入笔记正文或脚本。
6.2 下载前检查目录和空间
查看当前目录:
pwd
查看剩余磁盘空间:
df -h
下载大数据前尤其要确认:
- 当前路径是否在预期的数据盘,而不是 home 目录的小配额空间。
- 目标目录是否有足够空间。
- 下载失败后是否可以用
wget -c续传。
6.3 把下载任务放进 tmux
长时间下载应放在 tmux 中,避免 SSH 断开后任务中止:
tmux new -s download
wget -r -N -c -np \
--user YOUR_PHYSIONET_USERNAME \
--ask-password \
DATASET_URL
常用操作:
| 操作 | 命令或快捷键 | 作用 |
|---|---|---|
| 新建 session | tmux new -s download |
创建名为 download 的会话 |
| detach | Ctrl-b 然后按 d |
让任务在后台继续跑 |
| 查看 session | tmux ls |
列出已有会话 |
| 重新进入 | tmux attach -t download |
回到下载会话 |
7. CheXzero 与 MIMIC-CXR 数据准备
7.1 克隆 CheXzero
原教程后半部分使用 CheXzero 作为真实代码库示例:
git clone https://github.com/rajpurkarlab/CheXzero.git
cd CheXzero
如果远程服务器没有配置 GitHub SSH key,优先使用 HTTPS clone。
7.2 创建 CheXzero 环境并安装依赖
source activate base
conda create -n chexzero-demo python=3.9
conda activate chexzero-demo
pip install -r requirements.txt
原教程中提到可能遇到:
No matching distribution found for opencv-python-headless
原因是 requirements.txt 中固定的 opencv-python-headless==4.1.2.30 可能已经无法从 PyPI 获取。一个临时解决方式是去掉版本号,改成:
opencv-python-headless
这能绕过安装失败,但也可能引入依赖兼容性问题。更稳妥的方式是结合当前 Python 版本、PyTorch 版本和项目 README 重新锁定依赖。
7.3 下载 MIMIC-CXR 数据
CheXzero 训练需要 MIMIC-CXR 相关数据。原教程提到的入口是:
https://physionet.org/content/mimic-cxr-jpg/2.0.0/
完整数据很大,下载可能需要 12 小时以上。可以先下载小样本目录验证流程,再下载全量数据。
如果已经下载报告压缩包,可以解压:
unzip mimic-cxr-reports.zip
预处理时需要提供 chest X-ray 图像路径和 radiology reports 路径:
python run_preprocess.py \
--chest_x_ray_path=data/physionet.org/files/mimic-cxr-jpg/2.0.0/files \
--radiology_reports_path=data/physionet.org/files/mimic-cxr/2.0.0/files
预处理输出包括:
data/cxr_path.csvdata/cxr.h5data/mimic_expressions.csv
其中 cxr.h5 是 HDF5 文件,用于高效缓存图像数据。原教程指出,使用 h5 文件可以显著减少训练时反复读取图像文件的开销。
7.4 检查 h5 文件
可以在 notebook 或 Python 脚本中检查:
import h5py
f1 = h5py.File("../data/cxr.h5", "r+")
list(f1.keys())
f1["cxr"]
示例输出:
<HDF5 dataset "cxr": shape (7, 320, 320), type "<f4">
这表示 h5 文件里有一个名为 cxr 的 dataset,包含 7 张胸片,每张被存为 320 x 320 的数组。
7.5 运行 CheXzero 训练
从 CheXzero 仓库根目录运行:
python run_train.py \
--cxr_filepath "./data/cxr.h5" \
--txt_filepath "data/mimic_impressions.csv"
训练前需要确认:
cxr.h5路径正确。mimic_impressions.csv路径正确。- notebook 中没有同时打开同一个 h5 文件。
- PyTorch / CUDA 版本与当前 GPU driver 兼容。
8. 常见问题与排查
8.1 nvidia-smi 不存在或报错
可能原因:
- 当前机器没有 NVIDIA GPU。
- NVIDIA driver 没有安装或没有正确加载。
- 当前 shell / container 没有访问 GPU 的权限。
排查顺序:
hostname
nvidia-smi
先确认自己连接的是预期的 GPU 服务器,再检查 driver 和环境。
8.2 训练很慢但 GPU 空闲
常见原因:
- 没有执行
model.to(device)。 data和target没有执行.to(device)。torch.cuda.is_available()返回False。- DataLoader 太慢,GPU 在等数据。
排查方式:
- 在代码中打印
device。 - 用
watch -d -n 1 nvidia-smi观察训练开始后显存和利用率是否变化。 - 尝试增大
batch size或num_workers,并记录每个 epoch 的耗时。
8.3 h5 文件无法打开
原教程提到一个常见问题:notebook 中已经打开了 cxr.h5,训练脚本再次打开时会报错。解决方式是关闭 notebook kernel,或在 notebook 中执行:
f1.close()
8.4 h5 key 名称不匹配
如果训练代码期待 cxr_unprocessed,但实际 h5 文件中的 key 是 cxr,会出现找不到对象的错误。可以先检查 key:
list(f1.keys())
再把训练代码中的 key 改为实际存在的名称,例如 cxr。
8.5 CUDA 与 PyTorch 版本不匹配
如果遇到类似 “No kernel image is available for execution on the device” 的 CUDA 报错,需要检查当前 driver 支持的 CUDA 版本,以及安装的 PyTorch CUDA build。
查看 driver 侧 CUDA 信息:
nvidia-smi
必要时卸载并安装匹配版本的 PyTorch:
pip uninstall torch torchvision torchaudio
pip install torch==1.10.2+cu113 torchvision==0.11.3+cu113 torchaudio==0.10.2 \
--extra-index-url https://download.pytorch.org/whl/cu113
具体版本应根据当前项目、Python 版本、GPU 型号和 driver 支持范围调整。
原始教程要点
原始教程完整覆盖了 AWS EC2 版本的流程,主要包括:
- 使用 AWS EC2 创建 deep learning instance。
- 选择 Deep Learning AMI GPU PyTorch 镜像和合适的 GPU instance type。
- 创建
.pemkey pair,并通过chmod 400修正私钥权限。 - 配置 VS Code
Remote-SSH连接远程 instance。 - 在远程环境中使用
screenrc、zsh和oh-my-zsh改善开发体验。 - 修改 PyTorch 训练代码,使 model、data 和 target 使用
cuda。 - 使用
W&B记录训练指标和 epoch 耗时。 - 通过 batch size、
num_workers和 DataLoader 优化训练吞吐。 - 克隆并运行 CheXzero,处理 MIMIC-CXR 数据,排查依赖、h5 文件和 CUDA 版本问题。
这些内容在组内 GPU 服务器上仍然大多适用;需要替换的是 AWS instance 创建、key pair 和 EC2 连接部分。